/** @file    MethodsProvider.cpp
 *  @author  Alessandro Polo
 *  @version $Id: MethodsProvider.cpp 2621 2010-06-04 12:23:48Z alex $
 *  @brief
 * File containing methods for the wosh::MethodsProvider class.
 * The header for this class can be found in MethodsProvider.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include <core/MethodsProvider.h>

 #include <core/ObjectAllocator.h>
 #include <core/Object.h>
 #include <core/List.h>
 #include <core/Table.h>


using namespace std;
namespace wosh {

 WOSH_REGISTER(wosh::MethodsProvider, "", 1.01, _static_MethodsProvider)

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS

MethodsProvider::MethodsProvider( const Object* owner )
	: MapT<std::string, Method*>() {
	this->listPermission.setMask( Permission::Read, Permission::Read, Permission::Read );
	if ( owner == NULL ) return;
	this->listPermission = owner->getPermission();
 }

MethodsProvider::~MethodsProvider() {
	clear();
 }

//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////// SETTERS

WRESULT MethodsProvider::set( Method* method ) {
	if ( method == NULL ) return WRET_ERR_PARAM;
	Iterator lb = this->map.lower_bound( method->getName() );
	if( lb != this->map.end() && !(this->map.key_comp()( method->getName(), lb->first)) ) {
		return WRET_ERR_PARAM;
	 }
	else {
		// Use lb as a hint to insert, so it can avoid another lookup
		this->map.insert(lb, std::pair<std::string,Method*>(method->getName(), method));
	 }
	method->setPermission( this->listPermission, Permission::Overwrite_All, true );
	return WRET_OK;
 }

WRESULT MethodsProvider::unSet( const std::string& method_name ) {
	MutexLockerWrite mL(&this->mux);
	Iterator it = this->map.find(method_name);
	if ( it == this->map.end() )
		return WRET_ERR_PARAM;
	if ( it->second != NULL )
		delete it->second;
	this->map.erase(it);
	return WRET_OK;
 }

///////////////////////////////////////////////////////////////////////////////////////////////////// SETTERS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////// SETTERS

void MethodsProvider::setPermission( const Permission& value, short overwrite_mode, bool when_empty, bool nested )
 {
	this->listPermission.inherit( value, overwrite_mode, when_empty );
	if ( !nested )
		return;
	transactionBeginRead();
	ConstIterator it;
	const ConstIterator it_end = this->map.end();
	for( it=this->map.begin(); it!=it_end; ++it ) {
		if ( it->second == NULL ) continue;
		it->second->transactionBeginWrite();
		it->second->setPermission( this->listPermission, overwrite_mode, when_empty );
		it->second->transactionEnd();
	 }
	transactionEnd();
 }

///////////////////////////////////////////////////////////////////////////////////////////////////// SETTERS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////// HELPERS

List* MethodsProvider::toList( short index ) const {
	List* list = new List();
	transactionBeginRead();
	ConstIterator it;
	list->reserve( this->map.size() );
	const ConstIterator it_end = this->map.end();
	for( it=this->map.begin(); it!=it_end; ++it ) {
		if ( it->second == NULL ) continue;
		it->second->transactionBeginRead();
		switch(index) {
			case 3:		list->push_back<Variant>( it->second->getArguments().toString() ); break;
			case 2:		list->push_back( it->second->getPermission().clone() ); break;
			case 1:		list->push_back<Variant>( it->second->getDescription() ); break;
			case 0:
			default:	list->push_back<Variant>( it->second->getName() ); break;
		 }
		it->second->transactionEnd();
	 }
	transactionEnd();
	return list;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////

Table* MethodsProvider::toTable( bool include_permission, bool include_arguments ) const {
	transactionBeginRead();
	Table* table = new Table( this->map.size(), 2+(short)include_permission+(short)include_arguments, true );
	table->setTableName("Methods");
	table->setHeaderHorizontal("Name", 0);
	table->setHeaderHorizontal("Description", 1);
	if ( include_arguments )
		table->setHeaderHorizontal("Args", 2);
	if ( include_permission )
		table->setHeaderHorizontal("Permission", 2+(short)include_arguments);
	unsigned int iRow = 0;
	ConstIterator it;
	const ConstIterator it_end = this->map.end();
	for( it=this->map.begin(); it!=it_end; ++it, ++iRow ) {
		if ( it->second == NULL ) continue;
		it->second->transactionBeginRead();
		table->set<Variant>( it->second->getName(), iRow, 0 );
		table->set<Variant>( it->second->getDescription(), iRow, 1 );
		if ( include_arguments )
			table->set( it->second->getPermission().clone(), iRow, 2 );
		if ( include_permission )
			table->set( it->second->getArguments().clone(), iRow, 2+(short)include_arguments);
		it->second->transactionEnd();
	 }
	transactionEnd();
	return table;
 }

///////////////////////////////////////////////////////////////////////////////////////////////////// HELPERS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

}; // namespace wosh
